<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>查询树</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="rules.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="rules.html">快退</a></td><td width="60%" align="center" valign="bottom">章35. 规则系统</td><td width="10%" align="right" valign="top"><a href="rules.html">快进</a></td><td width="10%" align="right" valign="top"><a href="rules-views.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="QUERYTREE">35.1. 查询树</a></h1><a name="AEN38545"></a>
<p>要理解规则系统如何工作，首先要知道规则何时被激发以及它的输入和结果是什么。</p>
<p>规则系统位于分析器和规划器之间。以分析器输出的查询树以及用户定义的重写规则作为输入，重写规则也是一个查询树，只不过增加了一些扩展信息，然后创建零个或者多个查询树作为结果。所以它的输入和输出仍然是那些分析器可以生成的东西，因而任何规则系统看到的东西都是可以用 SQL 语句表达的。</p>
<p>那么什么是查询树呢?它是一个 SQL 语句的内部表现形式，这时组成该语句的每个独立部分都是分别存储的。如果你设置了配置参数 <tt class="VARNAME">debug_print_parse</tt>, <tt class="VARNAME">debug_print_rewritten</tt>, <tt class="VARNAME">debug_print_plan</tt> ，那么就可以在服务器日志中看到这些查询树。规则动作也是以查询树的方式存储的，存放在系统表 <tt class="STRUCTNAME">pg_rewrite</tt> 里面。不过不是用像调试输出那样的格式，但包含的内容是完全一样的。</p>
<p>阅读一个裸查询树需要一定的经验，但是因为理解查询树的 SQL 表现就足以理解规则系统，所以这份文档将不会告诉你如何读取它们。</p>
<p>当读取本章中查询树的 SQL 表现时，必须能够识别该语句被分解后放在查询树里的成员。查询树的成员有</p>
<div class="VARIABLELIST">
<dl>
<dt>命令类型(command type)</dt>
<dd><p>这是一个简单的值，说明哪条命令(<tt class="COMMAND">SELECT</tt>, <tt class="COMMAND">INSERT</tt>, <tt class="COMMAND">UPDATE</tt>, <tt class="COMMAND">DELETE</tt>)生成这个查询树。</p></dd>
<dt>范围表(range table)</dt>
<dd><p>范围表是一个查询中使用的关系的列表。在 <tt class="COMMAND">SELECT</tt> 语句里就是在 <tt class="LITERAL">FROM</tt> 关键字后面给出的关系。</p>
<p>每个范围表表示一个表或一个视图，表明是查询里哪个成员调用了它。在查询树里，范围表是用代号而不是用名字引用的，所以这里不用像在 SQL 语句里一样关心是否有重名问题。这种情况在引入了规则的范围表后可能会发生。本章的例子将不讨论这种情况。</p></dd>
<dt>结果关系(result relation)</dt>
<dd><p>这是一个范围表的索引，用于标识查询结果前往的表。</p>
<p><tt class="COMMAND">SELECT</tt> 查询通常没有结果关系表。特例 <tt class="COMMAND">SELECT INTO</tt> 几乎等于一个跟随 <tt class="LITERAL">INSERT ... SELECT</tt> 的 <tt class="COMMAND">CREATE TABLE</tt> ，所以这里就不单独讨论了。</p>
<p>在 <tt class="COMMAND">INSERT</tt>, <tt class="COMMAND">UPDATE</tt>, <tt class="COMMAND">DELETE</tt> 命令里，结果关系是更改发生影响的表或视图。</p></dd>
<dt>目标列(target list)</dt>
<dd><p>目标列是一列定义查询结果的表达式。在 <tt class="COMMAND">SELECT</tt> 的情况下，这些表达式就是构建查询的最终输出的东西。它们是位于 <tt class="COMMAND">SELECT</tt> 和 <tt class="COMMAND">FROM</tt> 关键字之间的表达式(<tt class="LITERAL">*</tt> 只是表明一个关系的所有字段的缩写，它被分析器扩展为独立的字段，因此规则系统永远看不到它)。</p>
<p><tt class="COMMAND">DELETE</tt> 不需要目标列是因为它们不产生任何结果。实际上规划器会向空目的标列中增加一条特殊的 CTID 记录。但这是在规则系统之后并且将稍后讨论；对于规则系统而言，目标列是空的。</p>
<p>对于 <tt class="COMMAND">INSERT</tt> 命令里面，目标列描述了应该进入结果关系的新行。这些行由那些在 <tt class="LITERAL">VALUES</tt> 子句里的表达式或在 <tt class="LITERAL">INSERT ... SELECT</tt> 语句里的 <tt class="COMMAND">SELECT</tt> 子句里面的表达式构成。重写过程的第一步就是为任何不是由原始的查询赋值，并且有缺省值的字段增加目标列表项。任何其它的字段(既无给出值也无缺省值)将由规划器自动赋予一个常量 NULL 表达式。</p>
<p>对于 <tt class="COMMAND">UPDATE</tt> 命令，目标列描述应该替换旧行的新行。在规则系统里，它只包含来自查询的 <tt class="LITERAL">SET column = expression</tt> 部分抽取的表达式。这时，规划器将通过插入从旧行抽取数据到新行的表达式的方法处理缺失的字段。并且它也会像在 <tt class="COMMAND">DELETE</tt> 里那样增加特殊的 CTID 记录。</p>
<p>目标列里的每个元素都包含着一个表达式，它可以为常量值、一个指向某个范围表里面的关系的一个字段的变量、一个由函数调用常量/变量/操作符等构成的表达式树。</p></dd>
<dt>条件(qualification)</dt>
<dd><p>查询条件是一个表达式，它非常类似那些包含在目标列里的条目。这个表达式的值是一个布尔值，通过此值来判断对最终结果行是否要执操作(<tt class="COMMAND">INSERT</tt>, <tt class="COMMAND">UPDATE</tt>, <tt class="COMMAND">DELETE</tt>, <tt class="COMMAND">SELECT</tt>)。它是一个 SQL 语句的 <tt class="LITERAL">WHERE</tt> 子句。</p></dd>
<dt>连接树(join tree)</dt>
<dd><p>查询的连接树显示了 <tt class="LITERAL">FROM</tt> 子句的结构。对于像 <tt class="LITERAL">SELECT ... FROM a, b, c</tt> 这样的简单查询，连接树只是一个 <tt class="LITERAL">FROM</tt> 项的简单列表，因为允许以任意顺序连接它们。但如果使用了 <tt class="LITERAL">JOIN</tt> 表达式(尤其是外连接的时候)，就必须按照该连接显示的顺序进行连接。连接树显示 <tt class="LITERAL">JOIN</tt> 表达式的结构。与特定的 <tt class="LITERAL">JOIN</tt> 子句(来自 <tt class="LITERAL">ON</tt> 或 <tt class="LITERAL">USING</tt> 表达式)相关的限制做为附加在那些连接树节点的条件表达式存储。事实证明把顶层 <tt class="LITERAL">WHERE</tt> 表达式也当做附加在顶层连接树项的条件来存储是非常方便的。所以实际上连接树代表  <tt class="COMMAND">SELECT</tt> 语句的 <tt class="LITERAL">FROM</tt> 和 <tt class="LITERAL">WHERE</tt> 子句。</p></dd>
<dt>其它(others)</dt>
<dd><p>查询树的其它部分，像 <tt class="LITERAL">ORDER BY</tt> 子句，不准备在这里讨论。规则系统在附加规则时将在那里(ORDER BY 子句)替换一些条目，但是这对于规则系统的基本原理并没有多大关系。</p></dd>
</dl>
</div>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="rules.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="rules-views.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">规则系统</td><td width="34%" align="center" valign="top"><a href="rules.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">视图和规则系统</td></tr>
</table>
</div>
</body></html>